<?php
class FrontController
{
    protected $_router;

    public function __construct(Router $router)
    {
        $this->_router = $router;
    }

    public function dispatch()
    {
        try
        {
            $response = FrontController::execute($this->_router);
        }
        catch (OutputResponseException $outputResponseEx)
        {
            $response = $outputResponseEx->response;
        }
        catch (NotFoundException $notFoundEx)
        {
            $response = FrontController::execute(Router::create(Config::get('error_controller')));
        }

        return $response;
    }

    public static function execute(Router $router)
    {
        $controllerPath = $router->getControllerPath();

        if (file_exists($controllerPath))
        {
            require_once($controllerPath);

            $controllerName = $router->getController();
            $actionName = 'action' . $router->getAction();

            $controller = new $controllerName();

            if (is_callable(array($controller, $actionName)))
            {
                $controller->preDispatch($router->getAction());

                $response = call_user_func_array(
                    array($controller, $actionName),
                    $router->getParams()
                );

                if ($response instanceof Response)
                {
                    return $response;
                }

                throw new ResponseException($router->getController(), $actionName);
            }
        }

        throw new NotFoundException($router->getRoute());
    }
}